package controllers

import (
	"net/http"
	"meman/models/auth"
	"meman/models/alert"
	"meman/models/events"
	"meman/sys/basic"
	"meman/models/nsq"
	"strings"
	"regexp"
	"strconv"
	"fmt"
	"github.com/labstack/echo"
	"github.com/chaosue/echo-sessions"
	"meman/libs/utils"
)

func NsqShow(c echo.Context) error {

	//session 使用
	session := sessions.Default(c)
	var username string
	//中间件已判断,所以这里不需要判断
	if user,ok := session.Get(USER_INFO_SESSION_KEY).(*auth.User); ok {
		username = user.Info.Username
	}

	//使用临时session存储保存消息
	alertInfo := new(alert.Alert)


	logger := basic.Logger{}

	host := utils.TrimSpace(c.QueryParam("host"))
	subscriberKey := utils.TrimSpace(c.QueryParam("subscriber_key"))
	messageClass := utils.TrimSpace(c.QueryParam("message_class"))


	//消息类型
	message := events.Message{}
	db := basic.Read()
	messages, err := message.GetMsgList(db, nil, 0, 999999999)
	if err != nil {
		alertInfo = &alert.Alert{Flag:false, Msg:append(alertInfo.Msg, "查询消息分类失败请检查")}
		logger.WriteMsg("error", "NsqShow: can not get msgList!")
	}

	//订阅者
	subscriber := events.Subscriber{}
	subscribers, err := subscriber.GetList(db, nil, 0, 999999999)
	if err != nil {
		alertInfo = &alert.Alert{Flag:false, Msg:append(alertInfo.Msg, ",查询订阅者失败请检查")}
		logger.WriteMsg("error", "NsqShow: can not get subscriberList!")
	}


	subscription := events.Subscription{}
	subscriptions, err := subscription.GetSubscriptionList(db, map[string]interface{}{"subscriber_key":subscriberKey}, 1, 9999999)
	if err != nil {
		alertInfo = &alert.Alert{Flag:false, Msg:append(alertInfo.Msg, "查询失败请检查")}
		logger.WriteMsg("error", "NsqShow: can not get subscriptionList!")
	}


	var nsqArray []map[string]interface{}
	nsqArray, err = getNsqArray(host, messageClass, subscriptions)
	if err != nil {
		alertInfo = &alert.Alert{Flag:false, Msg:append(alertInfo.Msg, err.Error())}
		logger.WriteMsg("error", "NsqShow: can not get nsq info!")
	}


	//"subscriptionIds":subscriberId, //TODO 这个在原有系统有现在没有用到,到时候问问是干嘛的
	c.Render(http.StatusOK, "nsqStats.tmpl", basic.H{
		"name":username,
		"host":host,
		"subscriberKey":subscriberKey,
		"messageClass":messageClass,
		"hosts": basic.Config.Nsq,
		"messageClasses":messages,
		"subscribers": subscribers,
		"data": nsqArray,
		"alert":alertInfo,

	})

	return nil

}


func getNsqArray(host string, msgName string, subscriptions []events.SubscriptionResult) ([]map[string]interface{}, error) {

	var nsqArray []map[string]interface{}

	//首层循环host,k有几个就说明有多少配置的host
	for _, v := range  basic.Config.Nsq  {
		for _,value := range v {

			//过滤host
			if host != "" && host != value.Host {
				continue
			}

			nsq,err := nsq.GetNsq(value.Host)
			if err != nil {
				return nil , fmt.Errorf("nsq获取失败,请检查配置.error:%s", err.Error())
			}

			var tmpTopics []map[string]interface{}
			tmpTopics = getTopics(nsq, msgName, subscriptions)

			nsqArray = append(nsqArray, map[string]interface{}{
				"host":value.Host,
				"topics":tmpTopics,
			})

		}

	}

	return nsqArray, nil
}

func getTopics(nsq *nsq.Nsq, msgName string, subscriptions []events.SubscriptionResult) []map[string]interface{}  {
	//次层循环topic, 每个host对应多少个topics
	var tmpTopics []map[string]interface{}

	for _, topic := range  nsq.Data.Topics  {

		//过滤topic name
		if msgName != "" && !strings.Contains(topic.TopicName, msgName+".") {
			continue
		}

		var tmpChannels []map[string]interface{}
		tmpChannels = getChannels(topic, subscriptions)

		tmpTopics = append(tmpTopics, map[string]interface{}{
			"topic_name":topic.TopicName,
			"channels":tmpChannels,
		})

	}

	return tmpTopics

}

func getChannels(topic nsq.Topic, subscriptions []events.SubscriptionResult) []map[string]interface{}  {

	var tmpChannels []map[string]interface{}

	for _, channel := range  topic.Channels  {
		//过滤channels
		var belongsToSubscriber bool
		for _, subscription := range subscriptions  {
			if ok, _ := regexp.MatchString("#."+strconv.Itoa(subscription.SubscriberId)+"(.FAIL)?$#", channel.ChannelName); ok {
				belongsToSubscriber = true
			}

			if !belongsToSubscriber {
				continue
			}
		}

		var readyCount int
		for _, client := range  channel.Clients  {
			readyCount += client.ReadyCount
		}

		tmpChannels = append(tmpChannels, map[string]interface{}{
			"channel_name":channel.ChannelName,
			"depth":channel.Depth,
			"in_flight_count":channel.InFlightCount,
			"deferred_count":channel.DeferredCount,
			"timeout_count":channel.TimeoutCount,
			"message_count":channel.MessageCount,
			"ready_count":readyCount,
		})
	}

	return tmpChannels
}
